/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.scs.ubbcluj.backend;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import edu.scs.ubbcluj.model.Attribute;
import edu.scs.ubbcluj.model.Database;
import edu.scs.ubbcluj.model.Table;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author Torok
 */
public class MongoDB {

    private static MongoClient mongoClient;
    static DB db;

    public static void connectToMongo() {

        try {
            mongoClient = new MongoClient("localhost");
        } catch (UnknownHostException ex) {
            Logger.getLogger(MongoDB.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void setDatastore(Database dataBase) {
        db = mongoClient.getDB(dataBase.getName());
    }

    public static void saveCollection(Table table, List<String> values) {
        DBCollection coll = db.getCollection(table.getName());
        int i = 0;
        String value = "";
        String key = "";
        for (Attribute attr : table.getPrimaryKeys()) {
            key = key + construct(attr, values.get(i));
            i++;
        }
        for (Attribute attr : table.getAttributes()) {
            value = value + construct(attr, values.get(i));
            i++;
        }
        for (Attribute attr : table.getForeignKeys()) {
            value = value + construct(attr, values.get(i));
            i++;
        }
        BasicDBObject doc = new BasicDBObject("key", key).append("value", value);
        coll.insert(doc);

    }

    public static void saveSpecCollection(Table table, List<String> values) {
        DBCollection coll = db.getCollection(table.getName());
        int i = 0;
        String value = "";
        for (Attribute attr : table.getAttributes()) {
            value = value + construct(attr, values.get(i));
            i++;
        }
        BasicDBObject doc = new BasicDBObject("value", value);
        coll.insert(doc);

    }
    public static String construct(Attribute attr, String value) {
        String helper = value;
        int nr = attr.getLength() - value.length();
        while (nr > 0) {
            helper = helper + " ";
            nr--;
        }
        return helper;
    }

    public static String construct(List<Attribute> attrList, List<String> values) {
        String val = "";
        int i = 0;
        for (Attribute attr : attrList) {
            val = val + construct(attr, values.get(i));
            i++;
        }
        return val;
    }

    public static void createCollection(Table table) {
        db.createCollection(table.getName(), new BasicDBObject());
    }

    public static void deleteDB(Database dataBase) {
        mongoClient.dropDatabase(dataBase.getName());
    }

    public static void deleteCollection(Table table) {
        DBCollection coll = db.getCollection(table.getName());
        coll.drop();
        for (Attribute attr : table.getindexedAttributes()) {
            coll = db.getCollection(table.getName() + attr.getName() + ".ind");
            coll.drop();
        }
        coll.drop();
    }

    public static boolean checkIfTableContains(Table table, int col, String value) {
        List<List<String>> content = getAll(table);
        for (List<String> row : content) {
            if (row.get(col).equals(value)) {
                return true;
            }
        }
        return false;
    }

    public static List<List<String>> getAll(Table table) {
        DBCollection coll = db.getCollection(table.getName());
        DBCursor cursor = coll.find();
        return getElements(table, cursor);
    }

    private static List<List<String>> getElements(Table table, DBCursor cursor) {
        List<List<String>> values = new ArrayList();
        try {
            while (cursor.hasNext()) {
                List<String> row = new ArrayList();
                DBObject o = cursor.next();
                String key = (String) o.get("key");
                if (key != null) {
                    for (Attribute attr : table.getPrimaryKeys()) {
                        int nr = attr.getLength();
                        String v = StringUtils.substring(key, 0, nr);
                        //System.out.println("key: *" + v + "*");
                        row.add(v);
                        key = key.substring(nr);
                    }
                }
                String value = (String) o.get("value");
                if (value != null) {
                    for (Attribute attr : table.getAttributes()) {
                        int nr = attr.getLength();
                        String v = StringUtils.substring(value, 0, nr);
                        //System.out.println("value: *" + v + "*");
                        row.add(v);
                        value = value.substring(nr);
                    }
                    for (Attribute attr : table.getForeignKeys()) {
                        int nr = attr.getLength();
                        String v = StringUtils.substring(value, 0, nr);
                        //System.out.println("value: *" + v + "*");
                        row.add(v);
                        value = value.substring(nr);
                    }
                }
                values.add(row);
            }
        } finally {
            cursor.close();
        }
        return values;
    }

    public static List<List<String>> getSpecElements(Table table, DBCursor cursor, List<Integer> specElem) {
        List<List<String>> values = new ArrayList();
        Integer i = 0;
        try {
            while (cursor.hasNext()) {
                List<String> row = new ArrayList();
                DBObject o = cursor.next();
                if (specElem.contains(i)) {
                    String key = (String) o.get("key");
                    if (key != null) {
                        for (Attribute attr : table.getPrimaryKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(key, 0, nr);
                            //System.out.println("key: *" + v + "*");
                            row.add(v);
                            key = key.substring(nr);
                        }
                    }
                    String value = (String) o.get("value");
                    if (value != null) {
                        for (Attribute attr : table.getAttributes()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            //System.out.println("value: *" + v + "*");
                            row.add(v);
                            value = value.substring(nr);
                        }
                        for (Attribute attr : table.getForeignKeys()) {
                            int nr = attr.getLength();
                            String v = StringUtils.substring(value, 0, nr);
                            //System.out.println("value: *" + v + "*");
                            row.add(v);
                            value = value.substring(nr);
                        }
                    }
                    values.add(row);
                }
                i++;
            }
        } finally {
            cursor.close();
        }
        return values;
    }

    public static void deleteRecord(Table table, String id) {
        DBCollection collection = db.getCollection(table.getName());
        BasicDBObject query = new BasicDBObject();
        query.append("key", id);
        collection.remove(query);
    }

    public static List<String> getRecordById(Table table, String id) {
        DBCollection collection = db.getCollection(table.getName());
        BasicDBObject query = new BasicDBObject();
        //tobbszoros primary key eseten igy nem jo:
        query.append("key", construct(table.getPrimaryKeys().get(0), id));
        DBCursor cursor = collection.find(query);
        List<List<String>> list = getElements(table, cursor);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    public static List<String> getRecordById(String fileName, String id) {
        // index allomanyok eseten egy rekord lekerdezese
        DBCollection collection = db.getCollection(fileName);
        BasicDBObject query = new BasicDBObject();
        query.append("key", id);
        DBCursor cursor = collection.find(query);
        List<String> row = new ArrayList();
        DBObject o = cursor.next();
        String key = (String) o.get("key");
        String value = (String) o.get("value");
        row.add(key);
        row.add(value);
        return row;
    }

    public static void createIndexOnPrimaryKey(String name, short order) {
        // name az table name vagy index allomany neve
        // order == 1 asc , order == -1 desc 
        DBCollection collection = db.getCollection(name);
        collection.createIndex(new BasicDBObject("key", order));
    }

    public static void createIndexOnUniqueKey(Table table, Attribute theAttr) {
        System.out.println("Unique key index");
        DBCollection coll = db.getCollection(table.getName() + theAttr.getName() + ".ind");
        List<List<String>> values = getAll(table);
        for (List<String> list : values) {
            String key = "";
            String value = "";
            int i = 0;
            for (Attribute attr : table.getPrimaryKeys()) {
                value = value + list.get(i);
                i++;
            }

            for (Attribute attr : table.getAttributes()) {
                if (attr.getName().equals(theAttr.getName())) {
                    key = key + list.get(i);
                    break;
                }
                i++;
            }

            for (Attribute attr : table.getForeignKeys()) {
                if (attr.getName().equals(theAttr.getName())) {
                    key = key + list.get(i);
                    break;
                }
                i++;
            }
            BasicDBObject doc = new BasicDBObject("key", key).append("value", value);
            coll.insert(doc);
        }

    }

    public static void createIndexOnUniqueKeyOneValue(Table table, Attribute theAttr, String key, String value) {
        //key - az ujonnan beszurt rekordbol az egyedi kulcs amire index volt kerve
        //value - a ujonnan beszurt rekord key erteke
        DBCollection coll = db.getCollection(table.getName() + theAttr.getName() + ".ind");
        BasicDBObject doc = new BasicDBObject("key", key).append("value", value);
        coll.insert(doc);
    }

    public static void createIndexOnNonUniqueKey(Table table, Attribute theAttr) {

        DBCollection coll = db.getCollection(table.getName() + theAttr.getName() + ".ind");
        List<List<String>> values = getAll(table);

        for (List<String> list : values) {
            String key = "";
            String value = "";
            int i = 0;
            for (Attribute attr : table.getPrimaryKeys()) {
                value = value + list.get(i);
                i++;
            }

            for (Attribute attr : table.getAttributes()) {
                if (attr.getName().equals(theAttr.getName())) {
                    key = key + list.get(i);
                    break;
                }
                i++;
            }

            for (Attribute attr : table.getForeignKeys()) {
                if (attr.getName().equals(theAttr.getName())) {
                    key = key + list.get(i);
                    break;
                }
                i++;
            }

            BasicDBObject doc = new BasicDBObject("key", key);
            DBObject ob = coll.findOne(doc);
            if (ob == null) {
                doc.append("value", value);
                coll.insert(doc);
            } else {
                String oldValue = (String) ob.get("value");
                String newValue = oldValue + "," + value;
                BasicDBObject newDoc = new BasicDBObject();
                newDoc.append("$set", new BasicDBObject().append("value", newValue));
                coll.update(doc, newDoc);
            }
        }
    }

    public static void createIndexNonOnUniqueKeyOneValue(Table table, Attribute theAttr, String key, String value) {
        //key - az ujonnan beszurt rekordbol az egyedi kulcs amire index volt kerve
        //value - a ujonnan beszurt rekord key erteke
        System.out.println("Non unique key one index");
        DBCollection coll = db.getCollection(table.getName() + theAttr.getName() + ".ind");
        BasicDBObject doc = new BasicDBObject("key", key);
        DBObject ob = coll.findOne(doc);
        if (ob == null) {
            doc.append("value", value);
            coll.insert(doc);
        } else {
            String oldValue = (String) ob.get("value");
            String newValue = oldValue + "," + value;
            BasicDBObject newDoc = new BasicDBObject();
            newDoc.append("$set", new BasicDBObject().append("value", newValue));
            coll.update(doc, newDoc);
        }
    }

    public static void deleteIndexedUniqueValue(String indName, String key) {
        DBCollection collection = db.getCollection(indName);
        BasicDBObject query = new BasicDBObject();
        query.append("key", key);
        collection.remove(query);
    }

    public static void deleteIndexedNonUniqueValue(String indName, String key, String value) {
        DBCollection coll = db.getCollection(indName);
        BasicDBObject doc = new BasicDBObject("key", key);
        DBObject ob = coll.findOne(doc);
        if (ob != null) {
            String oldValue = (String) ob.get("value");
            String newValue = "";
            String[] helper = oldValue.split(",");
            for (String s : helper) {
                if (!s.equals(value)) {
                    if (!newValue.equals("")) {
                        newValue = newValue + "," + s;
                    } else {
                        newValue = s;
                    }
                }
            }
            if (newValue.equals("")) {
                coll.remove(doc);
            } else {
                BasicDBObject newDoc = new BasicDBObject();
                newDoc.append("$set", new BasicDBObject().append("value", newValue));
                coll.update(doc, newDoc);
            }
        }
    }

    public static boolean valueExistsInIndex(String indName, String key, String value) {
        DBCollection coll = db.getCollection(indName);
        BasicDBObject doc = new BasicDBObject("key", key);
        DBObject ob = coll.findOne(doc);
        if (ob != null) {
            String oldValue = (String) ob.get("value");
            String[] helper = oldValue.split(",");
            for (String s : helper) {
                if (s.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean keyExistsInIndex(String indName, String key) {
        DBCollection coll = db.getCollection(indName);
        BasicDBObject doc = new BasicDBObject("key", key);
        DBObject ob = coll.findOne(doc);
        if (ob != null) {
            return true;
        }
        return false;
    }

}
